from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
from skopt import BayesSearchCV
from skopt.space import Real, Integer, Categorical
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# 加载数据
data = pd.read_csv("E:/GraduateDesign/LinearUse.csv")
X = data.drop(columns=['rrr'])
y = data['rrr']

# 处理零值（避免MAPE除零错误）
y = y.replace(0, 1e-6)  # 将零值替换为微小值

# 分割数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, shuffle=True)

# 定义贝叶斯搜索空间
search_spaces = {
    'n_estimators': Integer(50, 500),          # 树的数量
    'max_depth': Integer(3, 20),               # 最大深度（None表示不限）
    'min_samples_split': Integer(2, 20),       # 分裂最小样本数
    'min_samples_leaf': Integer(1, 20),        # 叶节点最小样本数
    'max_features': Real(0.1, 1.0, prior='uniform'),  # 特征采样比例
    'bootstrap': Categorical([True, False]),   # 是否使用有放回抽样
    'max_samples': Real(0.5, 1.0)              # 样本采样比例（当bootstrap=True时生效）
}

# 创建贝叶斯优化器
opt = BayesSearchCV(
    estimator=RandomForestRegressor(random_state=42),
    search_spaces=search_spaces,
    n_iter=50,          # 迭代次数（推荐50-100）
    cv=3,               # 交叉验证折数（平衡计算效率）
    n_jobs=-1,          # 使用全部CPU核心
    random_state=42,
    scoring='neg_mean_squared_error'  # 优化目标
)

# 执行参数优化（可能需要较长时间）
opt.fit(X_train, y_train)

# 输出最佳参数
print("Best parameters found:")
print(opt.best_params_)

# 使用最佳模型预测
best_model = opt.best_estimator_
y_pred = best_model.predict(X_test)

# 评估指标
print(f"\nRMSE: {mean_squared_error(y_test, y_pred, squared=False):.4f}")
print(f"MAE: {mean_absolute_error(y_test, y_pred):.4f}")
mape = np.mean(np.abs((y_test - y_pred) / y_test)) * 100  # 已处理零值
print(f"MAPE: {mape:.2f}%")
print(f"R²: {r2_score(y_test, y_pred):.4f}")

# 特征重要性可视化
plt.figure(figsize=(10, 6))
sorted_idx = best_model.feature_importances_.argsort()
plt.barh(X.columns[sorted_idx], best_model.feature_importances_[sorted_idx])
plt.xlabel("Random Forest Feature Importance")
plt.title("Feature Importance Ranking")
plt.tight_layout()
plt.show()